/**
 ******************************************************************************
 * @file    bsp_led.c
 * @author  Iron
 * @date    2020-01-01
 * @version v1.0
 * @brief   bsp_led c file
 */

/* Private includes ----------------------------------------------------------*/
#include "bsp_led.h"

/* Private typedef -----------------------------------------------------------*/
typedef struct _bsp_led_cfg
{
    GPIO_TypeDef *port;
    uint16_t pin;
} bsp_led_cfg_t;

typedef struct _bsp_led_status
{
    uint8_t state;
    uint8_t blink_en;       // 10Hz
    uint8_t blink_on;
    uint8_t blink_off;
    uint32_t blink_counter;
    uint32_t blink_count;
} bsp_led_status_t;


/* Private define ------------------------------------------------------------*/
#define BSP_LED_NUM     2

#define BSP_LED_GPIO_PORT_0   GPIOC
#define BSP_LED_GPIO_PIN_0    GPIO_PIN_13

#define BSP_LED_GPIO_PORT_1   GPIOB
#define BSP_LED_GPIO_PIN_1    GPIO_PIN_9

#define BSP_LED_GPIO_PORT_CLK_EN()  \
    __HAL_RCC_GPIOB_CLK_ENABLE(); \
    __HAL_RCC_GPIOC_CLK_ENABLE()


#define BSP_LED_SET(port, pin, status) HAL_GPIO_WritePin(port, pin, ((status) ? GPIO_PIN_RESET : GPIO_PIN_SET));

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static TX_TIMER led_timer;

static const bsp_led_cfg_t bsp_led_config[BSP_LED_NUM] =
{
    {BSP_LED_GPIO_PORT_0, BSP_LED_GPIO_PIN_0},
    {BSP_LED_GPIO_PORT_1, BSP_LED_GPIO_PIN_1},
};

static bsp_led_status_t bsp_led_status[BSP_LED_NUM];

/* Private function prototypes -----------------------------------------------*/

static void bsp_led_tmr_cb(ULONG id)
{
    for (int led_id = 0; led_id < BSP_LED_NUM; led_id++)
    {
        const bsp_led_cfg_t *led_cfg = &bsp_led_config[led_id];
        bsp_led_status_t *led_status = &bsp_led_status[led_id];

        if (led_status->blink_en)
        {
            led_status->blink_counter++;

            if (led_status->blink_counter <= led_status->blink_on)
            {
                BSP_LED_SET(led_cfg->port, led_cfg->pin, BSP_LED_ON);
            }
            else if (led_status->blink_counter <= led_status->blink_off)
            {
                BSP_LED_SET(led_cfg->port, led_cfg->pin, BSP_LED_OFF);
            }
            else
            {
                led_status->blink_counter = 0;

                if (led_status->blink_count != BSP_LED_BLINK_FOREVER)
                {
                    if (led_status->blink_count == 0)
                    {
                        led_status->blink_en = false;
                        led_status->blink_on = 0;
                        led_status->blink_off = 0;
                        led_status->blink_count = 0;

                        BSP_LED_SET(led_cfg->port, led_cfg->pin, led_status->state);
                    }
                    else
                    {
                        led_status->blink_count -= 1;
                    }
                }
            }
        }
    }
}

static int32_t bsp_led_tmr_init(void)
{
    tx_timer_create(&led_timer, "led_timer", bsp_led_tmr_cb,
                    0, TX_MS_TO_TICKS(100), TX_MS_TO_TICKS(100), TX_AUTO_ACTIVATE);

    return 0;
}

int32_t bsp_led_on(int32_t led_id)
{
    if (led_id < BSP_LED_NUM)
    {
        const bsp_led_cfg_t *led_cfg = &bsp_led_config[led_id];

        BSP_LED_SET(led_cfg->port, led_cfg->pin, BSP_LED_ON);
    }

    return led_id;
}

int32_t bsp_led_off(int32_t led_id)
{
    if (led_id < BSP_LED_NUM)
    {
        const bsp_led_cfg_t *led_cfg = &bsp_led_config[led_id];

        BSP_LED_SET(led_cfg->port, led_cfg->pin, BSP_LED_OFF);
    }

    return led_id;
}

int32_t bsp_led_bink(int32_t led_id, uint8_t state, uint8_t blink_on, uint8_t blink_off, uint32_t blink_count)
{
    if (led_id < BSP_LED_NUM)
    {
        bsp_led_status_t *led_status = &bsp_led_status[led_id];

        led_status->state = state;
        led_status->blink_on = blink_on;
        led_status->blink_off = blink_off;
        led_status->blink_count = blink_count;

        led_status->blink_en = true;
        led_status->blink_counter = 0;
    }

    return led_id;
}

int32_t bsp_led_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    BSP_LED_GPIO_PORT_CLK_EN();

    for (int i = 0; i < BSP_LED_NUM; i++)
    {
        const bsp_led_cfg_t *led_cfg = &bsp_led_config[i];

        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
        GPIO_InitStruct.Pull = GPIO_PULLUP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
        GPIO_InitStruct.Pin = led_cfg->pin;

        HAL_GPIO_Init(led_cfg->port, &GPIO_InitStruct);

        BSP_LED_SET(led_cfg->port, led_cfg->pin, BSP_LED_OFF);
    }

    bsp_led_tmr_init();

    return 0;
}

/**
 * @}
 */

/******************* (C)COPYRIGHT 2020 ***** END OF FILE *********************/
